/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.errorhandlers;

import android.content.Context;

import com.hercules.android.receiver.AndroidReceiver;
import com.hercules.android.receiver.LogUtil;
import com.hercules.android.receiver.handlers.commands.DuplicateXRECommandParameterException;
import com.hercules.android.receiver.handlers.commands.DuplicateXREObjectIdException;
import com.hercules.android.receiver.handlers.commands.InvalidXRECommandParameterException;
import com.hercules.android.receiver.handlers.commands.UnsupportedXRECommandParameterException;
import com.hercules.android.receiver.handlers.commands.XREApplicationNotConnectedException;
import com.hercules.android.receiver.handlers.commands.XREBadCommandIndexException;
import com.hercules.android.receiver.handlers.commands.XRECommandErrorHandler;
import com.hercules.android.receiver.handlers.commands.XRECommandHandlerException;
import com.hercules.android.receiver.handlers.commands.XREObjectCreationException;
import com.hercules.android.receiver.handlers.commands.XREObjectNotFoundException;
import com.hercules.android.receiver.handlers.commands.XREUnrecognizedCommandException;
import com.hercules.android.receiver.handlers.commands.XREViewFinderUtilityException;
import com.hercules.android.receiver.model.commands.XRECommand;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.logging.Logger;

/**
 * This implementation of {@link XRECommandErrorHandler} will store error information related to failed XRECommand to
 * configured file.
 * <p>
 * AndroidAssembly1 this class was added in Android Assembly 1
 * <p>
 * <b>Thread safety:</b> This class is mutable and performs operation on file. If processCommandError will be called
 * from one thread and properties will not be changed after they are initialized, this class is conditionally thread
 * safe.
 *
 * @author 7realm
 * @version 1.0
 */
public class DefaultXRECommandErrorHandler implements XRECommandErrorHandler {
    /** Represents logger for this class. */
    private static final Logger LOGGER = Logger.getLogger(DefaultXRECommandErrorHandler.class.getSimpleName());
    /**
     * Represents stored android {@link Context} that will allow operations on files.
     * <p>
     * Is set in constructor, cannot be null. Used in processCommandError method.
     */
    private final Context context;
    /**
     * Represents file name of log file.
     * <p>
     * Has getter and setter, can have any value.
     */
    private String fileName;

    /**
     * Constructor for class {@link DefaultXRECommandErrorHandler}.
     *
     * @param context the android context
     * @throws IllegalArgumentException if argument is null
     */
    public DefaultXRECommandErrorHandler(Context context) {
        checkNotNull(context, "context");

        this.context = context;
    }

    /**
     * Gets the file name of log file.
     *
     * @return the file name of log file
     */
    public String getFileName() {
        return fileName;
    }

    /**
     * Sets the file name of log file.
     *
     * @param fileName the file name of log file
     */
    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    /**
     * Handle given command error. If file name is set, it writes error details to file.
     *
     * @param error the error occurred which should be handled by this method
     * @param command the XRE command which causes the error
     * @param receiver the receiver for the XRE application
     */
    public void processCommandError(XRECommandHandlerException error, XRECommand command, AndroidReceiver receiver) {
        String methodName = "processCommandError";
        LogUtil.enter(LOGGER, this, methodName, error, command, receiver);

        try {
            checkNotNull(error, "error");
            checkNotNull(command, "command");
            checkNotNull(receiver, "receiver");

            if (fileName != null) {
                // open file stream
                PrintWriter writer =
                    new PrintWriter(context.openFileOutput(fileName, Context.MODE_APPEND | Context.MODE_WORLD_READABLE));

                writer.println("Error occurred while processing " + command.getCommand() + " command.");
                writer.println("Current Android Receiver URL " + receiver.getApplicationConnectData().getUrl() + ".");
                if (error instanceof XREApplicationNotConnectedException) {
                    writer.println("Application is not connected, but command is received");
                } else if (error instanceof XREViewFinderUtilityException) {
                    writer.println("Failed to find affected views");
                } else if (error instanceof XREBadCommandIndexException) {
                    XREBadCommandIndexException e = (XREBadCommandIndexException) error;
                    writer.println("Bad command index received " + e.getBadCommandIndex());
                } else if (error instanceof XREUnrecognizedCommandException) {
                    XREUnrecognizedCommandException e = (XREUnrecognizedCommandException) error;
                    writer.println("Unrecognized command received " + e.getUnrecognizedCommand());
                } else if (error instanceof DuplicateXRECommandParameterException) {
                    DuplicateXRECommandParameterException e = (DuplicateXRECommandParameterException) error;
                    writer.println("Duplicate command parameter " + e.getDuplicateParameter());
                } else if (error instanceof DuplicateXREObjectIdException) {
                    DuplicateXREObjectIdException e = (DuplicateXREObjectIdException) error;
                    writer.println("Duplicate XREObject ID " + e.getDuplicateId());
                } else if (error instanceof InvalidXRECommandParameterException) {
                    InvalidXRECommandParameterException e = (InvalidXRECommandParameterException) error;
                    writer.println("Invalid command parameter " + e.getParameter() + " value " + e.getInvalidValue());
                } else if (error instanceof UnsupportedXRECommandParameterException) {
                    UnsupportedXRECommandParameterException e = (UnsupportedXRECommandParameterException) error;
                    writer.println("Unsupported command parameter " + e.getUnsupportedParameter());
                } else if (error instanceof XREObjectCreationException) {
                    XREObjectCreationException e = (XREObjectCreationException) error;
                    writer.println("Failed to create object for class " + e.getFailedKlass());
                } else if (error instanceof XREObjectNotFoundException) {
                    XREObjectNotFoundException e = (XREObjectNotFoundException) error;
                    writer.println("Object with given ID " + e.getTargetId() + " was not found");
                }

                writer.println();

                // write common exception details
                error.printStackTrace(writer);
                writer.println();

                writer.flush();
            }

        } catch (IllegalArgumentException e) {
            LogUtil.error(LOGGER, this, methodName, e);
        } catch (FileNotFoundException e) {
            LogUtil.error(LOGGER, this, methodName, new XRECommandHandlerException(
                "I/O error occurred while opening output stream for '" + fileName + "' file."));
        }

        LogUtil.exit(LOGGER, this, methodName);
    }

    /**
     * Checks whether the given {@link Object} is null.
     *
     * @param arg the argument to check
     * @param name the name of the argument to check
     * @throws IllegalArgumentException if the given object is null
     */
    private static void checkNotNull(Object arg, String name) {
        if (arg == null) {
            throw new IllegalArgumentException("Argument '" + name + "' value should not be null.");
        }
    }
}
